以下是一個範例,我們一開始透過 fetch
方法從遠端 API 取得資料,並將取的回來的資料 data.Search
透過 set 函式更新到 movies
狀態,在這個過程中會發生什麼事情呢?
function App() {
const [movies, setMovies] = useState([]);
const [query, setQuery] = useState("");
fetch(`https://www.omdbapi.com/s={query}`)
.then((res) => res.json())
.then((data) => setMovies(data.Search));
}
movies
狀態更新時,元件會 重新渲染 並再次執行函式元件。fetch
行為會再次被觸發,進而再次更新 movies
狀態。是否已經察覺到問題了呢?這個元件會不斷重複 1 跟 2 的行為,導致無窮迴圈,因此,在這個地方直接執行 fetch
操作是不可行的。
useEffect 是 React 提供的一個 Hook,它用於處理元件中的副作用(Side Effect)操作,例如取得 API 資料、DOM 操作等。
function App() {
const [movies, setMovies] = useState([]);
const [query, setQuery] = useState("");
useEffect(() => {
fetch(`https://www.omdbapi.com/s={query}`)
.then((res) => res.json())
.then((data) => setMovies(data.Search));
})
}
這邊要特別注意,雖然我們已經將 API 操作放入 useEffect
內,但我們還缺少了一個非常重要的參數:依賴陣列。
function User({ userId }) {
const [user, setUser] = useState({});
const [query, setQuery] = useState("");
// 沒有傳遞依賴陣列,每次重新渲染都會執行這段 effect
useEffect(() => {
fetch(`https://www.omdbapi.com/s={query}`)
.then((res) => res.json())
.then((data) => setMovies(data.Search));
})
}
function App() {
const [movies, setMovies] = useState([]);
const [query, setQuery] = useState("");
// 傳遞一個依賴陣列,空陣列代表只有在初始渲染的時候執行一次
useEffect(() => {
fetch(`https://www.omdbapi.com/s={query}`)
.then((res) => res.json())
.then((data) => setMovies(data.Search));
}, [])
}
function App() {
const [movies, setMovies] = useState([]);
const [query, setQuery] = useState("");
// 初始渲染的時候執行一次
// 當 query 發生變化時,將重新執行這段 effect
useEffect(() => {
fetch(`https://www.omdbapi.com/s={query}`)
.then((res) => res.json())
.then((data) => setMovies(data.Search));
}, [query])
}
function App() {
const [movies, setMovies] = useState([]);
const [query, setQuery] = useState("");
// 初始渲染的時候執行一次
// 當 query 發生變化時,將重新執行這段 effect
useEffect(() => {
fetch(`https://www.omdbapi.com/s={query}`)
.then((res) => res.json())
.then((data) => setMovies(data.Search));
}, [query])
}
透過 useEffect
,我們能夠有效處理元件中的副作用操作,並通過適當設定依賴陣列,掌握何時運行這些操作,同時避免不必要的重新渲染。